﻿
/// <reference path="_namespace.js" />
/// <reference path="../components/Component.js" />
/// <reference path="Colour.js" />
/// <reference path="IGraphics.js" />

/*****************************************************************************
Ajax library class definition. Kevin Robinson 2006.
Class: ajax.drawing.GraphicsBase

Note: This class is to be considered *Abstract* as in itself it does "not much" but
define an interface (its own) to be used. It does however implement the get/set scale property.

It also has a line clipping method implemented as a Static method.

This means that a graphics object can either subclass this class or, if needed
can subclass another class but merely implement the interface of this class (IGraphics).
This gives the best of both worlds.
/*****************************************************************************/

ajax.lang.addNamespace("ajax.drawing");

//-----------------------------------------------------------------------------
ajax.drawing.GraphicsBase = function(doc, width, height)
{    
    ajax.drawing.GraphicsBase.superConstructor.call(this, doc);    
    
    this._scale = 1;    
    
    this.width      = width;
    this.height     = height;
    this.halfWidth  = width/2;
    this.halfHeight = height/2;    
}

//-----------------------------------------------------------------------------
ajax.lang.extend("ajax.drawing.GraphicsBase", "ajax.components.Component");
// Now say that we support the IGraphics interface
ajax.lang.supports("ajax.drawing.GraphicsBase", "ajax.drawing.IGraphics");
//-----------------------------------------------------------------------------

ajax.drawing.GraphicsBase.prototype.scaleWidth          = 0;
ajax.drawing.GraphicsBase.prototype.scaleHeight         = 0;
ajax.drawing.GraphicsBase.prototype.scaleAdjustedWidth  = 0;
ajax.drawing.GraphicsBase.prototype.scaleAdjustedHeight = 0;
ajax.drawing.GraphicsBase.prototype.halfWidth           = 0;
ajax.drawing.GraphicsBase.prototype.halfHeight          = 0;

// Now go ahead and support the actual Interface
//-----------------------------------------------------------------------------
ajax.drawing.GraphicsBase.prototype.setScale        = function(scale)
{
    this._scale = scale;
    
    var scaleMinus1 = this._scale - 1;
    
    this.scaleWidth     = scaleMinus1 * this.halfWidth;
    this.scaleHeight    = scaleMinus1 * this.halfHeight;
     
    var b     = this._scale * 2;
    var s     = this._scale + 1;
    var m = s/b;	    
    this.scaleAdjustedWidth     = this.width * m;
    this.scaleAdjustedHeight    = this.height * m;        
};
ajax.drawing.GraphicsBase.prototype.getScale        = function()
{
    return this._scale;
};    
    
ajax.drawing.GraphicsBase.prototype.width           = 0;
ajax.drawing.GraphicsBase.prototype.height          = 0;
ajax.drawing.GraphicsBase.prototype.setColor        = function(colour){};
ajax.drawing.GraphicsBase.prototype.drawLine        = function(x1, y1, x2, y2){};
ajax.drawing.GraphicsBase.prototype.drawPolyline3   = function(x1, y1, x2, y2, x3, y3){};
ajax.drawing.GraphicsBase.prototype.drawRect        = function(x, y, width, height){};
ajax.drawing.GraphicsBase.prototype.fillRect        = function(x, y, width, height){};
ajax.drawing.GraphicsBase.prototype.drawPolygon3    = function(x1, y1, x2, y2, x3, y3){};
ajax.drawing.GraphicsBase.prototype.fillPolygon3    = function(x1, y1, x2, y2, x3, y3){};
ajax.drawing.GraphicsBase.prototype.fillArc         = function(x, y, width, height, startAngle, arcAngle){};
ajax.drawing.GraphicsBase.prototype.drawEllipse     = function(x, y, width, height){};
ajax.drawing.GraphicsBase.prototype.fillEllipse     = function(x, y, width, height){};
ajax.drawing.GraphicsBase.prototype.setFont         = function(fontFamily, size, style){};
ajax.drawing.GraphicsBase.prototype.drawString      = function(str, x, y){};
ajax.drawing.GraphicsBase.prototype.addImage        = function(strFullUrl){};
ajax.drawing.GraphicsBase.prototype.drawImageFromRect = function(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight){};
ajax.drawing.GraphicsBase.prototype.drawImage       = function(domImage, x, y, width, height){};
ajax.drawing.GraphicsBase.prototype.drawImageToRect = function(domImage, destinationRect){};
ajax.drawing.GraphicsBase.prototype.clear           = function(colour){};
ajax.drawing.GraphicsBase.prototype.repaint         = function(){};
ajax.drawing.GraphicsBase.prototype.toString        = function(){ return "ajax.drawing.GraphicsBase"; };

// Statics...
//-----------------------------------------------------------------------------
//ClipLine(int &x1,int &y1,int &x2, int &y2)
ajax.drawing.GraphicsBase.clipLine = function(line, width, height)
{
	// this function clips the sent line to the screen dimensions
	
	// internal clipping codes
	var CLIP_CODE_C = 0x0000;
	var CLIP_CODE_N = 0x0008;
	var CLIP_CODE_S = 0x0004;
	var CLIP_CODE_E = 0x0002;
	var CLIP_CODE_W = 0x0001;

	var CLIP_CODE_NE = 0x000a;
	var CLIP_CODE_SE = 0x0006;
	var CLIP_CODE_NW = 0x0009;
	var CLIP_CODE_SW = 0x0005;

	var xc1=line.pointA.x;
	var	yc1=line.pointA.y; 
	var	xc2=line.pointB.x;
	var	yc2=line.pointB.y;

	var x1 = xc1;
	var y1 = yc1;
	var x2 = xc2;
	var y2 = yc2;

	var p1_code=0;
	var	p2_code=0;

	var min_clip_y = 0;
	var max_clip_y = height-1;
	var min_clip_x = 0;
	var max_clip_x = width-1;

	// determine codes for p1 and p2
	if (y1 < min_clip_y)
		p1_code|=CLIP_CODE_N;
	else
	if (y1 > max_clip_y)
		p1_code|=CLIP_CODE_S;

	if (x1 < min_clip_x)
		p1_code|=CLIP_CODE_W;
	else
	if (x1 > max_clip_x)
		p1_code|=CLIP_CODE_E;

	if (y2 < min_clip_y)
		p2_code|=CLIP_CODE_N;
	else
	if (y2 > max_clip_y)
		p2_code|=CLIP_CODE_S;

	if (x2 < min_clip_x)
		p2_code|=CLIP_CODE_W;
	else
	if (x2 > max_clip_x)
		p2_code|=CLIP_CODE_E;

	// try and trivially reject
	if ((p1_code & p2_code)) 
		return(0);

	// test for totally visible, if so leave points untouched
	if (p1_code==0 && p2_code==0)
		return(1);

	// determine end clip point for p1
	switch(p1_code)
		{
		case CLIP_CODE_C: break;

		case CLIP_CODE_N:
			{
			yc1 = min_clip_y;
			xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
			} break;
		case CLIP_CODE_S:
			{
			yc1 = max_clip_y;
			xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
			} break;

		case CLIP_CODE_W:
			{
			xc1 = min_clip_x;
			yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
			} break;
			
		case CLIP_CODE_E:
			{
			xc1 = max_clip_x;
			yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
			} break;

		// these cases are more complex, must compute 2 intersections
		case CLIP_CODE_NE:
			{
			// north hline intersection
			yc1 = min_clip_y;
			xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);

			// test if intersection is valid, of so then done, else compute next
				if (xc1 < min_clip_x || xc1 > max_clip_x)
					{
					// east vline intersection
					xc1 = max_clip_x;
					yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
					} // end if

			} break;
		  
		case CLIP_CODE_SE:
      		{
			// south hline intersection
			yc1 = max_clip_y;
			xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);	

			// test if intersection is valid, of so then done, else compute next
			if (xc1 < min_clip_x || xc1 > max_clip_x)
				{
				// east vline intersection
				xc1 = max_clip_x;
				yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
				} // end if

			} break;
		    
		case CLIP_CODE_NW: 
      		{
			// north hline intersection
			yc1 = min_clip_y;
			xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
			   
			// test if intersection is valid, of so then done, else compute next
			if (xc1 < min_clip_x || xc1 > max_clip_x)
				{
				xc1 = min_clip_x;
				yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);	
				} // end if

			} break;
		  	  
		case CLIP_CODE_SW:
			{
			// south hline intersection
			yc1 = max_clip_y;
			xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);	
			   
			// test if intersection is valid, of so then done, else compute next
			if (xc1 < min_clip_x || xc1 > max_clip_x)
				{
				xc1 = min_clip_x;
				yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);	
				} // end if

			} break;

		default:break;

		} // end switch

	// determine clip point for p2
	switch(p2_code)
		{
		case CLIP_CODE_C: break;

		case CLIP_CODE_N:
			{
			yc2 = min_clip_y;
			xc2 = x2 + (min_clip_y-y2)*(x1-x2)/(y1-y2);
			} break;

		case CLIP_CODE_S:
			{
			yc2 = max_clip_y;
			xc2 = x2 + (max_clip_y-y2)*(x1-x2)/(y1-y2);
			} break;

		case CLIP_CODE_W:
			{
			xc2 = min_clip_x;
			yc2 = y2 + (min_clip_x-x2)*(y1-y2)/(x1-x2);
			} break;
			
		case CLIP_CODE_E:
			{
			xc2 = max_clip_x;
			yc2 = y2 + (max_clip_x-x2)*(y1-y2)/(x1-x2);
			} break;

			// these cases are more complex, must compute 2 intersections
		case CLIP_CODE_NE:
			{
			// north hline intersection
			yc2 = min_clip_y;
			xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);

			// test if intersection is valid, of so then done, else compute next
				if (xc2 < min_clip_x || xc2 > max_clip_x)
					{
					// east vline intersection
					xc2 = max_clip_x;
					yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
					} // end if

			} break;
		  
		case CLIP_CODE_SE:
      		{
			// south hline intersection
			yc2 = max_clip_y;
			xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);	

			// test if intersection is valid, of so then done, else compute next
			if (xc2 < min_clip_x || xc2 > max_clip_x)
				{
				// east vline intersection
				xc2 = max_clip_x;
				yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
				} // end if

			} break;
		    
		case CLIP_CODE_NW: 
      		{
			// north hline intersection
			yc2 = min_clip_y;
			xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
			   
			// test if intersection is valid, of so then done, else compute next
			if (xc2 < min_clip_x || xc2 > max_clip_x)
				{
				xc2 = min_clip_x;
				yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);	
				} // end if

			} break;
		  	  
		case CLIP_CODE_SW:
			{
			// south hline intersection
			yc2 = max_clip_y;
			xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);	
			   
			// test if intersection is valid, of so then done, else compute next
			if (xc2 < min_clip_x || xc2 > max_clip_x)
				{
				xc2 = min_clip_x;
				yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);	
				} // end if

			} break;
		
		default:break;

		} // end switch

	// do bounds check
	if ((xc1 < min_clip_x) || (xc1 > max_clip_x) ||
		(yc1 < min_clip_y) || (yc1 > max_clip_y) ||
		(xc2 < min_clip_x) || (xc2 > max_clip_x) ||
		(yc2 < min_clip_y) || (yc2 > max_clip_y) )
		{
		return(0);
		} // end if

	// store vars back
	line.pointA.x = parseInt(xc1);
	line.pointA.y = parseInt(yc1);
	line.pointB.x = parseInt(xc2);
	line.pointB.y = parseInt(yc2);

	return(1);
}


//-----------------------------------------------------------------------------
ajax.drawing.GraphicsBase.cast = function(obj)
{///<returns type="ajax.drawing.GraphicsBase" />
    return obj;
}